<?php


namespace App\Web\Service;

use Exception;
use App\Exception\ExcludedException;
use App\Exception\NoSessionException;
use App\Exception\RightChangeException;
use App\Web\Model\Login as LoginModel;
use EchoPHP\Foundation\Exception\HttpException;
use EchoPHP\Http\Request;
use Firebase\JWT\ExpiredException;

class UserAuth {

    protected $request;
    protected $loginInfo;
    protected $authToken;

    /**
     * 全局错误信息
     * @var array
     */
    const STATUS_OK = 200;
    const STATUS_UNLOGIN = 480;
    const STATUS_FORBIDDEN = 481;
    const STATUS_UNLOGIN_NOSESSION = 482;
    const STATUS_EXCLUDED = 483;
    const STATUS_TOKEN_EXPIRED = 484;
    const STATUS_FORCE_MOIFYPWD = 485;
    const STATUS_RIGHT_CHANGED = 486;
    const STATUS_FORCE_BINDPHONE = 487;
    protected $statusMsg = [
        self::STATUS_OK => 'OK',
        self::STATUS_UNLOGIN => '您尚未登录',
        self::STATUS_FORBIDDEN => '对不起，您无权操作此功能',
        self::STATUS_UNLOGIN_NOSESSION => '由于长时间未操作，您已退出登录',
        self::STATUS_EXCLUDED => '您的账号已在其他地方登录',
        self::STATUS_TOKEN_EXPIRED => '登录已过期，请重新登录',
        self::STATUS_FORCE_MOIFYPWD => '请修改您的默认密码',
        self::STATUS_RIGHT_CHANGED => '系统权限已变更，请重新登录',
        self::STATUS_FORCE_BINDPHONE => '账号尚未绑定手机,请绑定您的手机号'
    ];

    /*
     * 全局错误信息
     */


    public function __construct(Request $request) {
        $this->request = $request;
    }

    /**
     * 判断登录状态
     * @param bool $throwException
     * @return bool
     * @throws \Exception
     */
    public function chkLogin($throwException = true) {
        if ($this->request->header()->has('authToken')) {
            $this->authToken = $this->request->header()->get('authToken');
        } elseif ($this->request->query()->has('t')) {
            $this->authToken = $this->request->query()->get('t');
        } elseif ($this->request->request()->has('t')) {
            $this->authToken = $this->request->request()->get('t');
        }
        $loginModel = new LoginModel();
        try {
            $loginInfo = $loginModel->check($this->authToken);
        } catch (ExpiredException $e) {
            if ($throwException) {
                throw new HttpException(self::STATUS_TOKEN_EXPIRED, $this->getStatusMsg(self::STATUS_TOKEN_EXPIRED));
            }
            $this->loginInfo = [];
            return false;
        } catch (NoSessionException $e) {
            if ($throwException) {
                $message = $e->getMessage();
                $message = $message ?: $this->getStatusMsg(self::STATUS_UNLOGIN_NOSESSION);
                throw new HttpException(self::STATUS_UNLOGIN_NOSESSION, $message);
            }
            $this->loginInfo = [];
            return false;
        } catch (ExcludedException $e) {
            if ($throwException) {
                throw new HttpException(self::STATUS_EXCLUDED, $this->getStatusMsg(self::STATUS_EXCLUDED));
            }
            $this->loginInfo = [];
            return false;
        } catch (RightChangeException $e) {
            if ($throwException) {
                throw new HttpException(self::STATUS_RIGHT_CHANGED, $this->getStatusMsg(self::STATUS_RIGHT_CHANGED));
            }
            $this->loginInfo = [];
            return false;
        } catch (Exception $e) {
            if ($throwException) {
                throw new HttpException(self::STATUS_UNLOGIN, $this->getStatusMsg(self::STATUS_UNLOGIN));
            }
            $this->loginInfo = [];
            return false;
        }

        $this->loginInfo = $loginInfo;
        return true;
    }

    /**
     * 获取登录token
     * @return mixed
     */
    public function getAuthToken() {
        return $this->authToken;
    }

    /**
     *  校验默认密码是否修改
     */
    public function chkForceModifyPwd() {
        $isDefaultPwd = $this->getLoginInfo('defaultpassword', 0);
        if ($isDefaultPwd == 1) {
            throw new HttpException(self::STATUS_FORCE_MOIFYPWD, $this->getStatusMsg(self::STATUS_FORCE_MOIFYPWD));
        }
    }

    /**
     *  校验是否绑定手机
     */
    public function chkBindPhone() {
        $isBindPhone = $this->getLoginInfo('mobileauth', 0);
        if ($isBindPhone != 1) {
            throw new HttpException(self::STATUS_FORCE_BINDPHONE, $this->getStatusMsg(self::STATUS_FORCE_BINDPHONE));
        }
    }

    /**
     * 验证用户权限
     * @param int $rightPosition
     * @return void
     * @throws \Exception
     */
    public function chkRight(int $rightPosition) {
        if ($rightPosition === RightCheck::RIGHT_SUPER_ADMIN) {
            return UserAuth::ckhSupperAdmin();
        }
        $rights = UserAuth::getLoginRights();
        if (substr($rights, $rightPosition, 1) != 1) {
            throw new HttpException(self::STATUS_FORBIDDEN, $this->getStatusMsg(self::STATUS_FORBIDDEN));
        }
    }

    /**
     * 判断是否超级管理员
     * @return void
     * @throws \Exception
     */
    public function ckhSupperAdmin() {
        if (1 != $this->getLoginInfo('superrole', 0)) {
            throw new HttpException(self::STATUS_FORBIDDEN, $this->getStatusMsg(self::STATUS_FORBIDDEN));
        }
    }

    /**
     * 判断是否超级管理员
     * @return bool
     * @throws \Exception
     */
    public function ckhSuperLeader() {
        return 1 == $this->getLoginInfo('superrole', 0);
    }

    /**
     * 判断是否团队管理员
     * @return bool
     * @throws \Exception
     */
    public function ckhTeamLeader() {
        return 2 == $this->getLoginInfo('teamrole', 1);
    }

    /**
     * 获取登录信息
     * @param null $key
     * @param null $default
     * @return bool|null
     * @throws \Exception
     */
    public function getLoginInfo($key = null, $default = null) {
        if (is_null($this->loginInfo)) {
            $this->chkLogin(false);
        }
        if (is_null($key)) {
            return $this->loginInfo;
        }
        return isset($this->loginInfo[$key]) ? $this->loginInfo[$key] : $default;
    }

    /**
     * 获取登录人id
     * @return bool|null
     * @throws \Exception
     */
    public function getLoginId() {
        return $this->getLoginInfo('userid', 0);
    }

    /**
     * 获取当前登录人用户名
     * @return bool|null
     * @throws \Exception
     */
    public function getLoginUsername() {
        return $this->getLoginInfo('username', '');
    }

    /**
     * 获取当前登录人登录名
     * @return bool|null
     * @throws \Exception
     */
    public function getLoginCname() {
        return $this->getLoginInfo('cname', '');
    }

    /**
     * 获取登录人拥有的权限
     * @return bool|null
     * @throws \Exception
     */
    public function getLoginRights() {
        return $this->getLoginInfo('rights', '');
    }

    /**
     * 根据全局错误码获取全局错误信息
     * @param $status
     * @return mixed|string
     */
    public function getStatusMsg($status) {
        return isset($this->statusMsg[$status]) ? $this->statusMsg[$status] : '系统繁忙，请稍后再试';
    }
}